
#include "utils.h"
#include "addlog.h"
#include <iomanip>
//#define BOOST_REGEX_NO_LIB
#include <boost/regex.hpp>
//using namespace RegexClass;
//#include "Player_Window.h"
//---------------------------------------------------------------------------

//ExecuteCommand = (ExecuteCommandFunc) 0x0047EA20;

void (*uPrint)(int r,const char *text,...) = (void(*)(int,const char*,...))0x004b3800;


string ToStr(int number)
{
	   stringstream ss;
	   ss << number;
	   return ss.str();
}
string ToStr(double number)
{
	   stringstream ss;
	   ss.precision(5);
	   ss << number;
	   return ss.str();
}


ArgContainer::ArgContainer(string arg)
{
	argc = 0;
	int word_start = 0;
	int closing;
	while(1)
	{
	if(arg[word_start] == '"')
	{
		word_start++;
		closing = arg.find_first_of('"', word_start);
		if(closing == -1)
			closing = arg.length();
	}
	else if(arg[word_start] == '\'')
	{
		word_start++;
		closing = arg.find_first_of('\'', word_start);
		if(closing == -1)
			closing = arg.length();
	}
	else
	{
		closing = arg.find_first_of(' ', word_start);
		if(closing == -1)
			closing = arg.length();
	}
	string word = arg.substr(word_start, closing-word_start);
	args.push_back(word);
	argc++;
	word_start = arg.find_first_not_of(' ', closing+1);
	if(word_start == -1)
		break;

	if(arg[word_start+1] == '"' || arg[word_start+1] == '\'')
		word_start++;
	}

}

string ArgContainer::operator[](size_t i)
{
	if(i<args.size())
		return args[i];
	return "";
}

// *** Player messing-with stuff ****
playerindex IndtoReverse(playerindex ind)
{
	//ind *= 2;
/*
1:
2:abyll
3:john
4:me
5:
6:
7:gOd
...
(Pl_ind == 3)
(return==2)*/

	// take player (pl_list: 1-16) and give reverse-index (as for (list_get (players) IND)))
	//int num = Form1->PlayerHeader->SlotsTaken;
	vector<playerindex> indices; // thats the index for each player that is on,
	//string out = "";
	for(int i=15; i>=0; i--)
	{
		if(Server()->IsOn(i)){
			//out += string(i);
			indices.push_back(i);
		} else//[GOD,me,John,Abyll] 's slot ind
		{
			//out += "(" + string(server.GetPlayer(i)->PlayerID) + ")";
		}
	}
	for (size_t i=0; i <indices.size(); i++) {
		if (indices[i] == ind) {
			return i;
		}
	}
	return -1;
}

// The name matching engine. A: check for exact match to a name. B: regex matching. *C: Player nickname matching.
// (* = not implemented yet)
bool NameMatch(Static_Player* pl, string str)
{
	string name = WidetoString(wstring(pl->Name));

	// First, substitute in the correct regex syntax.
	size_t pos=0;
	while(1)
	{
		pos = str.find("?",pos);
		if(pos<0 || pos == string.npos)
			break;
		str.replace(pos, 1, ".");
		pos++;
	}
	pos = 0;
	while(1)
	{
		pos = str.find("*",pos);
		if(pos<0 || pos == string.npos)
			break;
		str.replace(pos, 1,".*");
		pos += 2; // to skip past what I replaced.
	}
	//uPrint(0, "found *'s");
	bool matches = false;
	const boost::regex re(name);
	return regex_match(str, re);
}

bool isnumber(string str)
{
	for(size_t i=0; i<str.length(); i++)
		if(!isdigit(str[i]))
			return false;
	return true;
}
//---------------------------------------------------------------------------

/*void SwapTeam(playerindex ind)
{
	Static_Player* pl = Server()->GetPlayer(ind);
	if (pl->Team != 1)
	{
		pl->Team = 1;
		pl->iTeam = 1;
		Server()->alterplayers[ind - 1].Team = 1;
	}else
	{
		pl->Team = 0;
		pl->iTeam = 0;
		Server()->alterplayers[ind - 1].Team = 0;
	}
}*/

void LagPlayer(playerindex ind, bool lag)
{
	if (IndtoReverse(ind) == -1) {
        return;
    }
	stringstream cmd;
	cmd << "unit_suspended (unit (list_get (players) " << IndtoReverse(ind);
	cmd << ")) " << lag;
	Server()->ExecCmd(cmd.str().c_str());
}
//---------------------------------------------------------------------------

void Tokenize(const string& str, vector<string>& tokens, const string& delimiters = " ")
{
	// Skip delimiters at beginning.
	string::size_type lastPos = str.find_first_not_of(delimiters, 0);
	// Find first "non-delimiter".
	string::size_type pos	 = str.find_first_of(delimiters, lastPos);

	while (string::npos != pos || string::npos != lastPos)
	{
		// Found a token, add it to the vector.
		tokens.push_back(str.substr(lastPos, pos - lastPos));
		// Skip delimiters.  Note the "not_of"
		lastPos = str.find_first_not_of(delimiters, pos);
		// Find next "non-delimiter"
		pos = str.find_first_of(delimiters, lastPos);
	}
}

//---------------------------------------------------------------------------
string GetCoord(float coord[3])
{
	stringstream next;
	next.setf(ios::fixed | ios::showpoint);
	next.precision(3);
	next << coord[0] << ", " << coord[1] << ", " << coord[2];
	return next.str();
}
//---------------------------------------------------------------------------
bool TextToCoord(string text, float *coord)
{
	//vector<short> ind;
	vector<string> coords;
	string othertext = text.c_str();
	Tokenize(othertext, coords, ", ");
	if (coords.size() == 3)
	{
		try
		{
			if(!sscanf_s(coords[0].c_str(), "%f", coord+0))
				return false;
			if(!sscanf_s(coords[1].c_str(), "%f", coord+1))
				return false;
			if(!sscanf_s(coords[2].c_str(), "%f", coord+2))
				return false;
			//coord[2] = AnsiString(coords[2].c_str()).ToDouble();
			//Form1->Edt_Coord->Text = "Success!! " + AnsiString(coord[0]) + AnsiString(coord[1]) + AnsiString(coord[2]);
			return true;
		}
//		catch (Exception &exception)
//		{
//			Application->ShowException(&exception);
//		}
		catch(...)
		{
			//Form1->Edt_Coord->Text = "Put real numbers!";
		}
	}
	return false;
}
//---------------------------------------------------------------------------

bool GoodFile(string filename)
{
	
	boost::regex re(filename, boost::regex::icase);

	// No navigating anywhere else!
	if(regex_match(".*\\\\.*", re))
		return false;

	// And no working with executable files
	if(regex_match(".*\\.dll", re))
		return false;
	if(regex_match(".*\\.exe", re))
		return false;

	return true;
}

void FileAppend(string filename, string line)
{
	filename = Manager()->save_dir + filename;
	if(!GoodFile(filename))
		return;

	line = "\n" + line;
	ofstream file;
	file.open(filename.c_str(), ios::app | ios::out);
	if(file.rdstate())
	{
		file.close();
		uPrint(0, "bad file");
		return;
	}
	file.write(line.c_str(), line.size());
	file.close();
	uPrint(0, "Line [%s] added to file %s", line.c_str(), filename.c_str());
}

string WidetoString(wstring& widestr)
{
	//....Example of WideCharToMultiByte
	vector<char> temp; // that many chars, + NULL termination
	temp.resize((widestr.length()+1));
	//bool defaultedchar = false;
	WideCharToMultiByte(
		CP_THREAD_ACP, // code page
		NULL, // performance and mapping flags
		widestr.c_str(), // wide-character string
		widestr.length(), // number of chars in string
		&temp[0], // buffer for new string (must use vector here!)
		widestr.length()+1, // size of buffer
		NULL, // default for unmappable chars
		NULL // set when default char used
	);
	return string(&temp[0]);
}
wstring StringtoWide(string& thestr)
{
	//....Example of WideCharToMultiByte
	vector<wchar_t> temp(thestr.length()+1);
	//bool defaultedchar = false;
	MultiByteToWideChar(
		CP_UTF7, // code page
		NULL, // performance and mapping flags
		thestr.c_str(), // wide-character string
		thestr.length(), // number of chars in string
		&temp[0], // buffer for new string (must use vector here!)
		thestr.length()+1 // size of buffer
	);
	return wstring(&temp[0]);
}

bool CanDoCmd(const char* CmdStr, short admin)
{
	string cmd(CmdStr);
	int temp = 9999;
	//bool match;

	if(cmd.length() < 1) // guarantee that there's at least a command there.
		return false;

	boost::regex re(CmdStr, boost::regex::icase);

	vector<CIniFile::Record> list;
	CIniFile::Load(Manager()->save_dir + "commands.ini", list);
	for(size_t i=0; i<list.size(); i++)
	{
		if(regex_match(list[i].Key.c_str(), re))
		{
			sscanf_s(list[i].Value.c_str(), "%d", &temp);
			uPrint(0, "cmd match on %s, %s: admin:%d", list[i].Key.c_str(), list[i].Value.c_str(), temp);
			if(admin < temp)
				return false;
			else
				return true;
		}
	}
	if(admin > 20)
		return true;
	return false;
}